package network;

import gate.IGate;

import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import org.jhotdraw.draw.action.ButtonFactory;


import sr.logger.Logger;
import task.Task;
import util.ResponsePackage;
import util.Tuple;
import utils.Settings;
import utils.TaskFactory;
import views.GameWindow;
import views.MainWindow;

import master.ChildInterface;
import master.MasterInterface;


public class MasterCommunicator extends Thread 
{
	Logger logger = Logger.getLogger(MasterCommunicator.class);
	ReceiverImpl receiver;
	BlockingQueue<Task> jobQueue = new LinkedBlockingQueue<Task>();
	private static MasterCommunicator instance;
	private MasterInterface master;
	private boolean connected = false;
	private boolean shutdown = false;
	MainWindow mainWindow;
	GameWindow gameWindow;
	private ChildInterface childInterface;
	private IGate gate;
	public void addTask(Task task)
	{
		jobQueue.add(task);
	}
	private MasterCommunicator()
	{
		
		
		try {
			receiver = new ReceiverImpl();
		} catch (RemoteException e) {
			e.printStackTrace();
		}
	}
	public void shutdown() { shutdown = true; } 
	public synchronized static MasterCommunicator getMasterCommunicator()
	{
		if(instance == null)
		{
			instance = new MasterCommunicator();
		}
		return instance;
	}
	@Override
	public void run()
	{
		while(!shutdown)
		{
			Task job  = null;
			try {
				job = jobQueue.poll(1, TimeUnit.SECONDS);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			if(job != null)
			{
				try
				{
					job.run();
				}
				catch(RuntimeException e)
				{
					onRemoteException(job);
				}
						
			}
		}
	}
	private void onRemoteException(Task job)
	{
		try
		{
			Tuple<Boolean,MasterInterface> response = gate.isDown(master);
			if(response.first)
			{
				System.out.println("Yes server down");
				master = response.second;
			}
			job.updateReference(master, childInterface);
			TaskFactory.setUpFactory(master);
			job.run();
			
		} catch (RemoteException e)
		{
			e.printStackTrace();
			System.err.println("Two exception in row, " +
					"and gate is telling that current active is alive");
		}
	}
	public void connectToMaster() throws AccessException, RemoteException, NotBoundException
	{
		logger.log("connectToMaster");
		if(connected)
			return;
		connected = true;
		logger.log("connectToMaster","registering");
		gate = (IGate)LocateRegistry.getRegistry("89.78.151.6").lookup("Gate");
		master = gate.getServer();
		//master = (MasterInterface)LocateRegistry.getRegistry().lookup("Server");
		
		ResponsePackage<Long> rPackage = master.register(receiver);
		Settings.getSettings().setMyId(rPackage.data);
		logger.log(rPackage.timer, "connectToMaster","onReceive");
		TaskFactory.setUpFactory(master);
		Runtime.getRuntime().addShutdownHook(new Thread()
		{
			@Override
			public void run()
			{
				try {
					master.unregister(Settings.getSettings().getMyId(),logger.log("run","unregistering"));
					UnicastRemoteObject.unexportObject(receiver, true);
				} catch (RemoteException e) {
					e.printStackTrace();
				}
			}
		});
		this.start();
	}
	public void setMainWindowRef(MainWindow mainWindow) {
		this.mainWindow = mainWindow;
		receiver.setMainWindowRef(mainWindow);
	}
	public void setGameWindowRef(GameWindow gameWindow)
	{
		this.gameWindow = gameWindow;
		receiver.setGameWindowRef(gameWindow);
		
	}
	public void setChildRef(ChildInterface childInterface)
	{
		this.childInterface = childInterface;
		TaskFactory.setChildInterface(childInterface);
	}
	
}
